package com.learn.demo.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class NIOGroupDemoServer {
    private static Selector selector;
    private static ServerSocketChannel serverSocketChannel;
    private final int PORT = 8888;

    public NIOGroupDemoServer() {
        try {
            serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.socket().bind(new InetSocketAddress(PORT));
            selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println(String.format("服务器启动，监听%d端口", PORT));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void listen() throws Exception {
        while (true) {
            int listenSelects = selector.select();
            if (listenSelects == 0) {
                //等待客户端连接
            }
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> selectionKeyIterator = selectionKeys.iterator();
            while (selectionKeyIterator.hasNext()) {
                SelectionKey selectionKey = selectionKeyIterator.next();
                if (selectionKey.isAcceptable()) {
                    //客户端连接处理
                    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    socketChannel.configureBlocking(false);
                    //注册监听selector OP_READ事件
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    System.out.println("客户端连接,OP_ACCEPT事件，selectionKey.hashCode()：" + selectionKey.hashCode());
                    System.out.println("客户端地址:" + socketChannel.getRemoteAddress());
                }
                if (selectionKey.isReadable()) {
                    SocketChannel socketChannel = null;
                    try {
                        socketChannel = (SocketChannel) selectionKey.channel();
                        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                        int readCount = socketChannel.read(byteBuffer);
                        if (readCount > 0) {
                            System.out.println("客户端连接,OP_READ事件,selectionKey.hashCode()：" + selectionKey.hashCode());
                            String msg = new String(byteBuffer.array());
                            System.out.println("收到客户端消息：" + msg);
                            //转发消息给其他客户端
                            for (SelectionKey key : selector.keys()) {
                                Channel channel = key.channel();
                                if (channel instanceof SocketChannel && channel != socketChannel) {
                                    ((SocketChannel) channel).write(ByteBuffer.wrap(msg.getBytes()));
                                }
                            }
                        }
                    } catch (IOException e) {
                        System.out.println("客户端" + socketChannel.getRemoteAddress() + ",断开连接, selectionKey.hashCode()：" + selectionKey.hashCode());
                        selectionKey.cancel();
                        socketChannel.close();
                    }

                }
                selectionKeyIterator.remove();
            }
        }
    }

    public static void main(String[] args) {
        try {
            NIOGroupDemoServer server = new NIOGroupDemoServer();
            server.listen();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                selector.close();
                serverSocketChannel.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }
}
